home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cfengine-1.5.3 / src / client.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-12  |  19.2 KB  |  812 lines

  1. /* 
  2.  
  3.         Copyright (C) 1995
  4.         Free Software Foundation, Inc.
  5.  
  6.    This file is part of GNU cfengine - written and maintained 
  7.    by Mark Burgess, Dept of Computing and Engineering, Oslo College,
  8.    Dept. of Theoretical physics, University of Oslo
  9.  
  10.    This program is free software; you can redistribute it and/or modify it
  11.    under the terms of the GNU General Public License as published by the
  12.    Free Software Foundation; either version 2, or (at your option) any
  13.    later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.   You should have received a copy of the GNU General Public License
  21.   along with this program; if not, write to the Free Software
  22.   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  23.  
  24. */
  25.  
  26. /*******************************************************************/
  27. /*                                                                 */
  28. /* File Image copying                                              */
  29. /*                                                                 */
  30. /* client part for remote copying                                  */
  31. /*                                                                 */
  32. /*******************************************************************/
  33.  
  34. #define INET 1
  35.  
  36. #include "cf.defs.h"
  37. #include "cf.extern.h"
  38.  
  39. /* Protocol specs:
  40.  
  41.    Pre authorization: CAUTH (clear text auth) client-name server-name user-name
  42.  
  43.    Stat file:  SYNCH long-time-string STAT filename
  44.            reply with OK: <stat-reply-string>
  45.            keep open channel
  46.  
  47.    md5 file    Checksum compare
  48.  
  49.    Get file:   GET filename
  50.  
  51.            reply with <multiple buffers>, break on zero length buffer
  52.            or BAD: <message>
  53.            keep open channel for more stat/get
  54.  
  55.    Opendir:    OPENDIR dir-name
  56.  
  57.            reply with <multiple buffers>, break on zero length buffer
  58.  
  59.    Exec:       EXEC option-string
  60.               reply with <multiple buffers>, break on zero length buffer
  61.                Close after this.
  62.  
  63. Replies:
  64.  
  65.   OK: message (succeeded)
  66.  
  67.   BAD: message (failed)
  68.    
  69.  */
  70.  
  71. /*********************************************************************/
  72. /* Level 1                                                           */
  73. /*********************************************************************/
  74.  
  75. OpenServerConnection(serverlist,ip)
  76.  
  77. struct Item *serverlist;
  78. struct Image *ip;
  79.  
  80. { int TimeOut(),err;
  81.   struct sockaddr_in cin;
  82.  
  83. if (strcmp(ip->server,"localhost") == 0)
  84.    {
  85.    AUTHENTICATED = true;
  86.    return true;
  87.    }
  88.  
  89. AUTHENTICATED = false; 
  90.  
  91. if (SD == cf_not_connected)
  92.    {
  93.    Debug("Opening server connnection to %s\n",ip->server);
  94.    bzero(&cin,sizeof(cin));
  95.  
  96.    cin.sin_port = PORTNUMBER;
  97.    cin.sin_addr.s_addr = (ip->dns)->s_addr;
  98.    cin.sin_family = AF_INET; 
  99.    
  100.    Debug("Trying to connect to %s = %s, port h=%d\n",ip->server,inet_ntoa(cin.sin_addr),PORTNUMBER);
  101.   
  102.    if ((SD = socket(AF_INET,SOCK_STREAM,0)) == -1)
  103.       {
  104.       CfLog(cferror,"","socket");
  105.       AUTHENTICATED = false;
  106.       return false;
  107.       }
  108.    
  109.    signal(SIGALRM,(void *)TimeOut);
  110.    alarm(CF_TIMEOUT);
  111.    
  112.    if (err=connect(SD,(void *) &cin,sizeof(cin)) == -1)
  113.       {
  114.       sprintf(OUTPUT,"Couldn't connect to host %s\n",ip->server);
  115.       CfLog(cfinform,OUTPUT,"connect");
  116.       CloseServerConnection();
  117.       AUTHENTICATED = false;
  118.       return false;
  119.       }
  120.    
  121.    alarm(0);
  122.    signal(SIGALRM,SIG_DFL);
  123.    
  124.    Debug("Sending on socket...%d\n",SD);
  125.  
  126.    if (! IdentifyForVerification(SD,VFQNAME))
  127.       {
  128.       CfLog(cferror,"Server registration procedure failed","");
  129.       errno = EPERM;
  130.       CloseServerConnection();
  131.       AUTHENTICATED = false;
  132.       return false;
  133.       }
  134.  
  135.    AUTHENTICATED = true;
  136.    return true;
  137.    }
  138. else
  139.    {
  140.    Debug("Server connection to %s already open on %d\n",ip->server,SD);
  141.    }
  142.  
  143. AUTHENTICATED = true; 
  144. return true; 
  145. }
  146.  
  147. /*********************************************************************/
  148.  
  149. CloseServerConnection()
  150.  
  151. {
  152. Debug("Closing current connection\n");
  153. close(SD);
  154. SD = cf_not_connected;
  155. }
  156.  
  157. /*********************************************************************/
  158.  
  159. cf_rstat(file,buf,ip,stattype)
  160.  
  161. /* If a link, this reads readlink and sends it back in the same
  162.    package. It then caches the value for each copy command */
  163.  
  164. char *file;
  165. struct stat *buf;
  166. struct Image *ip;
  167. char *stattype;
  168.  
  169. { char sendbuffer[bufsize];
  170.   char recvbuffer[bufsize];
  171.   char in[bufsize],out[bufsize];
  172.   struct cfstat cfst;
  173.   int i,ret;
  174.   time_t tloc;
  175.   struct hostent *hp;
  176.  
  177. Debug("cf_rstat(%s)\n",file);
  178.  
  179. if (strlen(file) > bufsize-30)
  180.    {
  181.    CfLog(cferror,"Filename too long","");
  182.    return -1;
  183.    }
  184.  
  185. ret = GetCachedStatData(file,buf,ip,stattype);
  186.  
  187. if (ret != 0)
  188.    {
  189.    return ret;
  190.    }
  191.  
  192. if ((tloc = time((time_t *)NULL)) == -1)
  193.    {
  194.    CfLog(cferror,"Couldn't read system clock\n","");
  195.    }
  196.  
  197. sendbuffer[0] = '\0';
  198.  
  199. if (ip->secure)
  200.    {
  201. #ifdef HAVE_LIBCRYPTO
  202.    bzero(in,bufsize);
  203.    bzero(out,bufsize);
  204.    bzero(sendbuffer,bufsize);
  205.    sprintf(in,"SYNCH %d STAT %s",tloc,file);
  206.    cfencrypt(in,out,CFDES1,CFDES2,CFDES3,strlen(in));
  207.    sprintf(sendbuffer,"SSYNCH %d",strlen(in));
  208.    bcopy(out,sendbuffer+23,bufsize-24);
  209. #endif   
  210.    }
  211. else
  212.    {
  213.    sprintf(sendbuffer,"SYNCH %d STAT %s",tloc,file);
  214.    }
  215.  
  216. if (send(SD,sendbuffer,bufsize,0) == -1)
  217.    {
  218.    CfLog(cferror,"Can't send on socket","send");
  219.    return -1;
  220.    }
  221.  
  222. if (RecvSocketStream(SD,recvbuffer,bufsize,0) == -1)
  223.    {
  224.    return -1;
  225.    }
  226.  
  227. if (strstr(recvbuffer,"unsynchronized"))
  228.    {
  229.    CfLog(cferror,"Clocks differ too much to do copy by date (security)","");
  230.    CfLog(cferror,recvbuffer+4,"");
  231.    return -1;
  232.    }
  233.  
  234. if (strncmp(recvbuffer,"BAD",3) == 0)
  235.    {
  236.    sprintf(OUTPUT,"Server returned error: %s\n",recvbuffer+4);
  237.    CfLog(cfverbose,OUTPUT,"");
  238.    errno = EPERM;
  239.    return -1;
  240.    }
  241.  
  242. if (strncmp(recvbuffer,"OK:",3) == 0)
  243.    {
  244.    int d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12=0;
  245.    
  246.    sscanf(recvbuffer,"OK: %1d %5d %12d %12d %12d %12d %12d %12d %12d %12d %12d %12d",
  247.       &d1,&d2,&d3,&d4,&d5,&d6,&d7,&d8,&d9,&d10,&d11,&d12);
  248.  
  249.    cfst.cf_type = (enum cf_filetype) d1;
  250.    cfst.cf_mode = (mode_t) d2;
  251.    cfst.cf_lmode = (mode_t) d3;
  252.    cfst.cf_uid = (uid_t) d4;
  253.    cfst.cf_gid = (gid_t) d5;
  254.    cfst.cf_size = (off_t) d6;
  255.    cfst.cf_atime = (time_t) d7;
  256.    cfst.cf_mtime = (time_t) d8;
  257.    cfst.cf_ctime = (time_t) d9;
  258.    cfst.cf_makeholes = (char) d10;
  259.    ip->makeholes = (char) d10;
  260.    cfst.cf_ino = d11;
  261.    cfst.cf_nlink = d12;
  262.  
  263.    /* Use %?d here to avoid memory overflow attacks */
  264.  
  265.    Debug("Mode = %d,%d\n",d2,d3);
  266.    
  267.    Debug("OK: type=%d\n mode=%o\n lmode=%o\n uid=%d\n gid=%d\n size=%ld\n atime=%d\n mtime=%d ino=%d nlnk=%d\n",
  268.     cfst.cf_type,cfst.cf_mode,cfst.cf_lmode,cfst.cf_uid,cfst.cf_gid,(long)cfst.cf_size,
  269.     cfst.cf_atime,cfst.cf_mtime,cfst.cf_ino,cfst.cf_nlink);
  270.  
  271.    bzero(recvbuffer,bufsize);
  272.    
  273.    if (RecvSocketStream(SD,recvbuffer,bufsize,0) == -1)
  274.       {
  275.       return -1;
  276.       }
  277.    
  278.    Debug("Linkbuffer: %s\n",recvbuffer);
  279.  
  280.    if (strlen(recvbuffer) > 3)
  281.       {
  282.       cfst.cf_readlink = strdup(recvbuffer+3);
  283.       }
  284.    else
  285.       {
  286.       cfst.cf_readlink = NULL;
  287.       }
  288.  
  289.    switch (cfst.cf_type)
  290.       {
  291.       case cf_reg:   cfst.cf_mode |= (mode_t) S_IFREG;
  292.                  break;
  293.       case cf_dir:   cfst.cf_mode |= (mode_t) S_IFDIR;
  294.                     break;
  295.       case cf_char:  cfst.cf_mode |= (mode_t) S_IFCHR;
  296.                  break;
  297.       case cf_fifo:  cfst.cf_mode |= (mode_t) S_IFIFO;
  298.                  break;
  299.       case cf_sock:  cfst.cf_mode |= (mode_t) S_IFSOCK;
  300.                  break;
  301.       case cf_block: cfst.cf_mode |= (mode_t) S_IFBLK;
  302.                  break;
  303.       }
  304.  
  305.  
  306.    cfst.cf_filename = strdup(file);
  307.    cfst.cf_server =  strdup(ip->server);
  308.  
  309.    if ((cfst.cf_filename == NULL) ||(cfst.cf_server) == NULL)
  310.       {
  311.       FatalError("Memory allocation in cf_rstat");
  312.       }
  313.    
  314.    cfst.cf_failed = false;
  315.  
  316.    if (cfst.cf_lmode != 0)
  317.       {
  318.       cfst.cf_lmode |= (mode_t) S_IFLNK;
  319.       }
  320.  
  321.    CacheData(&cfst,ip);
  322.  
  323.    if ((cfst.cf_lmode != 0) && (strcmp(stattype,"link") == 0))
  324.       {
  325.       buf->st_mode = cfst.cf_lmode;
  326.       }
  327.    else
  328.       {
  329.       buf->st_mode = cfst.cf_mode;
  330.       }
  331.  
  332.    buf->st_uid = cfst.cf_uid;
  333.    buf->st_gid = cfst.cf_gid;
  334.    buf->st_size = cfst.cf_size;
  335.    buf->st_mtime = cfst.cf_mtime;
  336.    buf->st_ctime = cfst.cf_ctime;
  337.    buf->st_atime = cfst.cf_atime;
  338.    buf->st_ino   = cfst.cf_ino;
  339.    buf->st_nlink = cfst.cf_nlink;
  340.    
  341.    return 0;
  342.    }
  343.  
  344.  
  345. sprintf(OUTPUT,"Protocol error in stat (shouldn't happen). Got [%s]\n",recvbuffer); 
  346. CfLog(cfinform,OUTPUT,"");
  347. errno = EPERM;
  348.  
  349. return -1;
  350. }
  351.  
  352. /*********************************************************************/
  353.  
  354. CFDIR *cf_ropendir(dirname,ip)
  355.  
  356. char *dirname;
  357. struct Image *ip;
  358.  
  359. { char sendbuffer[bufsize];
  360.   char recvbuffer[bufsize];
  361.   int i,offset,n, done=false;
  362.   CFDIR *cfdirh;
  363.   char *sp;
  364.  
  365. Debug("CfOpenDir(%s:%s)\n",ip->server,dirname);
  366.  
  367. if (strlen(dirname) > bufsize - 20)
  368.    {
  369.    CfLog(cferror,"Directory name too long");
  370.    return NULL;
  371.    }
  372.  
  373. if ((cfdirh = (CFDIR *)malloc(sizeof(CFDIR))) == NULL)
  374.    {
  375.    CfLog(cferror,"Couldn't allocate memory in cf_ropendir\n","");
  376.    exit(1);
  377.    }
  378.  
  379. cfdirh->cf_list = NULL;
  380. cfdirh->cf_listpos = NULL;
  381. cfdirh->cf_dirh = NULL;
  382.  
  383. sprintf(sendbuffer,"OPENDIR %s",dirname);
  384.  
  385. if (send(SD,sendbuffer,bufsize,0) == -1)
  386.    {
  387.    return NULL;
  388.    }
  389.  
  390. while (!done)
  391.    {
  392.    if ((n = RecvSocketStream(SD,recvbuffer,bufsize,0)) == -1)
  393.       {
  394.       if (errno == EINTR) 
  395.          {
  396.          continue;
  397.          }
  398.       return false;
  399.       }
  400.  
  401.    if (n == 0)
  402.       {
  403.       break;
  404.       }
  405.  
  406.    if (strncmp(recvbuffer,CFFAILEDSTR,strlen(CFFAILEDSTR)) == 0)
  407.       {
  408.       sprintf(OUTPUT,"Network access to %s:%s denied\n",ip->server,dirname);
  409.       CfLog(cfinform,OUTPUT,"");
  410.       return false;      
  411.       }
  412.  
  413.    if (strncmp(recvbuffer,"BAD:",4) == 0)
  414.       {
  415.       sprintf(OUTPUT,"%s\n",recvbuffer+4);
  416.       CfLog(cfinform,OUTPUT,"");
  417.       return false;      
  418.       }
  419.  
  420.    for (sp = recvbuffer; *sp != '\0'; sp++)
  421.       {
  422.       if (strncmp(sp,CFD_TERMINATOR,strlen(CFD_TERMINATOR)) == 0)        /* End transmission */
  423.      {
  424.      cfdirh->cf_listpos = cfdirh->cf_list;
  425.      return cfdirh;
  426.      }
  427.  
  428.       AppendItem(&(cfdirh->cf_list),sp,NULL);
  429.       
  430.       while(*sp != '\0')
  431.      {
  432.      sp++;
  433.      }
  434.       }
  435.    }
  436.  
  437. cfdirh->cf_listpos = cfdirh->cf_list;
  438. return cfdirh;
  439. }
  440.  
  441. /*********************************************************************/
  442.  
  443. FlushClientCache(ip)
  444.  
  445. struct Image *ip;
  446.  
  447. {
  448. if (ip->cache)
  449.    {
  450.    free(ip->cache);
  451.    ip->cache = NULL;
  452.    }
  453. }
  454.  
  455. /*********************************************************************/
  456.  
  457. CompareMD5Net(file1,file2,ip)
  458.  
  459. char *file1, *file2;
  460. struct Image *ip;
  461.  
  462. { static unsigned char d[16];
  463.   char sendbuffer[bufsize];
  464.   char recvbuffer[bufsize],in[bufsize],out[bufsize];
  465.   int i,offset;
  466.  
  467. Debug("Send digest of %s to server\n",file2);
  468. cfMDFile(file2,d);   /* send this to the server for comparison */
  469.  
  470. bzero(recvbuffer,bufsize);
  471. bzero(sendbuffer,bufsize);
  472.  
  473. if (20 + 3*16 + strlen(file1) > bufsize-1)
  474.    {
  475.    CfLog(cferror,"MD5 transfer overflow...updating for safety\n","");
  476.    return true;
  477.    }
  478.  
  479.  
  480. if (ip->secure)
  481.    {
  482. #ifdef HAVE_LIBCRYPTO
  483.    bzero(in,bufsize);
  484.    bzero(out,bufsize);
  485.    bzero(sendbuffer,bufsize);
  486.    sprintf(in,"MD5 %s\n %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \0",file1,
  487.        d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10],d[11],d[12],d[13],d[14],d[15]);
  488.    cfencrypt(in,out,CFDES1,CFDES2,CFDES3,strlen(in));
  489.    sprintf(sendbuffer,"SMD5 %d",strlen(in));
  490.    bcopy(out,sendbuffer+23,bufsize-24);
  491. #endif   
  492.    }
  493. else
  494.    {
  495.    sprintf(sendbuffer,"MD5 %s\n %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \0",file1,
  496.        d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10],d[11],d[12],d[13],d[14],d[15]);
  497.    } 
  498.  
  499. if (send(SD,sendbuffer,bufsize,0) == -1)
  500.    {
  501.    CfLog(cferror,"","send");
  502.    return false;
  503.    }
  504.  
  505. if (RecvSocketStream(SD,recvbuffer,bufsize,0) == -1)
  506.    {
  507.    Verbose("No answer from host, assuming checksum ok to avoid remote copy for now...\n");
  508.    return false;
  509.    }
  510.  
  511. if (strcmp(CFD_TRUE,recvbuffer) == 0)
  512.    {
  513.    Debug("MD5 mismatch: %s\n",recvbuffer);
  514.    return true; /* mismatch */
  515.    }
  516. else
  517.    {
  518.    Debug("MD5 match: %s\n",recvbuffer);
  519.    return false;
  520.    }
  521.  
  522. /* Not reached */
  523. }
  524.  
  525. /*********************************************************************/
  526.  
  527. CopyRegNet(source,new,ip,size)
  528.  
  529. char *source, *new;
  530. struct Image *ip;
  531. off_t size;
  532.  
  533. { int dd, buf_size, TimeOut(), i=0;
  534.   char *buf,*cp,*sp,in[bufsize],out[bufsize],sendbuffer[bufsize],key[8];
  535.   int n_read, *intp,err,toget,towrite,len;
  536.   long n_read_total = 0;
  537.   int last_write_made_hole = 0, done = false;
  538.  
  539. Debug("CopyRegNet(%s,%s,%d) to socket %d\n",source,new,size,SD);
  540.  
  541. if ((strlen(new) > bufsize-20))
  542.    {
  543.    CfLog(cferror,"Filename too long","");
  544.    return false;
  545.    }
  546.  
  547. unlink(new);  /* To avoid link attacks */ 
  548.   
  549. if ((dd = open(new,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600)) == -1)
  550.    {
  551.    sprintf(OUTPUT,"Copy %s:%s security - failed attempt to exploit a race? (Not copied)\n",ip->server,new);
  552.    CfLog(cferror,OUTPUT,"open");
  553.    unlink(new);
  554.    return false;
  555.    }
  556.  
  557. sendbuffer[0] = '\0';
  558.  
  559. if (ip->secure)
  560.    {
  561. #ifdef HAVE_LIBCRYPTO
  562.    des_random_key(key);
  563.    bzero(in,bufsize);
  564.    bzero(out,bufsize);
  565.    bzero(sendbuffer,bufsize);
  566.    sprintf(in,"GET %8.8s %s",key,source);
  567.    cfencrypt(in,out,CFDES1,CFDES2,CFDES3,strlen(in));
  568.    sprintf(sendbuffer,"SGET %4d %4d",strlen(in),ST_BLKSIZE(dstat));
  569.    bcopy(out,sendbuffer+31,bufsize-32);
  570. #endif
  571.    }
  572. else
  573.    {
  574.    sprintf(sendbuffer,"GET %d %s",ST_BLKSIZE(dstat),source);
  575.    }
  576.  
  577. if (send(SD,sendbuffer,bufsize,0) == -1)
  578.    {
  579.    CfLog(cferror,"Couldn't send","send");
  580.    close(dd);
  581.    return false;
  582.    }
  583.  
  584. buf_size = ST_BLKSIZE(dstat);
  585. buf = (char *) malloc(bufsize + sizeof(int)); /* Note bufsize not buf_size */
  586.  
  587. n_read_total = 0;
  588.  
  589. while (!done)
  590.    {
  591.    if ((size - n_read_total)/buf_size > 0)
  592.       {
  593.       toget = towrite = buf_size;
  594.       }
  595.    else if (size != 0)
  596.       {
  597.       towrite = (size - n_read_total);
  598.       toget = buf_size; /* padding required for encryption chaining */
  599.       }
  600.    else
  601.       {
  602.       toget = towrite = 0;
  603.       }
  604.  
  605.    if ((n_read = RecvSocketStream(SD,buf,toget,0)) == -1)
  606.       {
  607.       if (errno == EINTR) 
  608.          {
  609.          continue;
  610.          }
  611.  
  612.       close(dd);
  613.       free(buf);
  614.       return false;
  615.       }
  616.  
  617.    if (strncmp(buf,CFFAILEDSTR,strlen(CFFAILEDSTR)) == 0)
  618.       {
  619.       sprintf(OUTPUT,"Network access to %s:%s denied\n",ip->server,source);
  620.       RecvSocketStream(SD,buf,bufsize-toget,0); /* flush rest of transaction */
  621.       CfLog(cfinform,OUTPUT,"");
  622.       close(dd);
  623.       free(buf);
  624.       return false;      
  625.       }
  626.  
  627.    if (strncmp(buf,"BAD:",4) == 0) /* error */
  628.       {
  629.       CfLog(cfinform,buf+4,"");
  630.       close(dd);
  631.       free(buf);
  632.       return false;      
  633.       }
  634.  
  635.    if (ip->secure)
  636.       {
  637.       bzero(sendbuffer,bufsize);
  638.       cfdecrypt(buf,sendbuffer,CFDES1,key,CFDES3,buf_size);
  639.       bcopy(sendbuffer,buf,buf_size);
  640.       }
  641.  
  642.    if (n_read == 0)
  643.       {
  644.       break;
  645.       }
  646.  
  647.    n_read_total += towrite; /*n_read;*/
  648.  
  649.    if (n_read_total >= (long)size)  /* Handle EOF without closing socket */
  650.       {                                 /* signature is 8 bytes */
  651.       done = true;
  652.       }
  653.  
  654.    intp = 0;
  655.  
  656.    if (ip->makeholes)
  657.       {
  658.       buf[n_read] = 1;                       /* Sentinel to stop loop.  */
  659.  
  660.       /* Find first non-zero *word*, or the word with the sentinel.  */
  661.  
  662.       intp = (int *) buf;
  663.  
  664.       while (*intp++ == 0)
  665.          {
  666.          }
  667.  
  668.       /* Find the first non-zero *byte*, or the sentinel.  */
  669.  
  670.       cp = (char *) (intp - 1);
  671.  
  672.       while (*cp++ == 0)
  673.          {
  674.          }
  675.  
  676.       /* If we found the sentinel, the whole input block was zero,
  677.          and we can make a hole.  */
  678.  
  679.       if (cp > buf + n_read)
  680.          {
  681.          /* Make a hole.  */
  682.          if (lseek (dd,(off_t)n_read,SEEK_CUR) < 0L)
  683.             {
  684.             sprintf (OUTPUT,"lseek in CopyReg, dest=%s\n", new);
  685.             CfLog(cferror,OUTPUT,"lseek");
  686.             free(buf);
  687.         unlink(new);
  688.         close(dd);
  689.             return false;
  690.             }
  691.          last_write_made_hole = 1;
  692.          }
  693.       else
  694.          {
  695.          /* Clear to indicate that a normal write is needed. */
  696.          intp = 0;
  697.          }
  698.       }
  699.  
  700.    if (intp == 0)
  701.       {
  702.       if (cf_full_write (dd,buf,towrite) < 0)
  703.          {
  704.      sprintf(OUTPUT,"CopyReg(%s:%s,%s) failed\n",ip->server,source,new);
  705.          CfLog(cferror,OUTPUT,"");
  706.          close(dd);
  707.          free(buf);
  708.      unlink(new);
  709.          return false;
  710.          }
  711.       last_write_made_hole = 0;
  712.       }
  713.    }
  714.  
  715.   /* If the file ends with a `hole', something needs to be written at
  716.      the end.  Otherwise the kernel would truncate the file at the end
  717.      of the last write operation.  */
  718.  
  719.   if (last_write_made_hole)
  720.     {
  721.     /* Write a null character and truncate it again.  */
  722.  
  723.     if (cf_full_write (dd,"",1) < 0 || ftruncate (dd,n_read_total) < 0)
  724.        {
  725.        CfLog(cferror,"cfengine: full_write or ftruncate error in CopyReg\n","");
  726.        free(buf);
  727.        unlink(new);
  728.        close(dd);
  729.        return false;
  730.        }
  731.     }
  732.  
  733. close(dd);
  734. free(buf);
  735. return true;
  736. }
  737.  
  738. /*********************************************************************/
  739. /* Level 2                                                           */
  740. /*********************************************************************/
  741.  
  742. GetCachedStatData(file,statbuf,ip,stattype)
  743.  
  744. char *file;
  745. struct stat *statbuf;
  746. struct Image *ip;
  747. char *stattype;
  748.  
  749. { struct cfstat *sp;
  750.  
  751. Debug("GetCachedStatData(%s)\n",file);
  752.  
  753. for (sp = ip->cache; sp != NULL; sp=sp->next)
  754.    {
  755.    if ((strcmp(ip->server,sp->cf_server) == 0) && (strcmp(file,sp->cf_filename) == 0))
  756.       {
  757.       if (sp->cf_failed)  /* cached failure from cfopendir */
  758.      {
  759.      errno = EPERM;
  760.      Debug("Cached failure to stat\n");
  761.      return -1;
  762.      }
  763.  
  764.       if ((strcmp(stattype,"link") == 0) && (sp->cf_lmode != 0))
  765.      {
  766.      statbuf->st_mode  = sp->cf_lmode;
  767.      }
  768.       else
  769.      {
  770.          statbuf->st_mode  = sp->cf_mode;
  771.      }
  772.  
  773.       statbuf->st_uid   = sp->cf_uid;
  774.       statbuf->st_gid   = sp->cf_gid;
  775.       statbuf->st_size  = sp->cf_size;
  776.       statbuf->st_atime = sp->cf_atime;
  777.       statbuf->st_mtime = sp->cf_mtime;
  778.       statbuf->st_ctime = sp->cf_ctime;
  779.       statbuf->st_ino   = sp->cf_ino;
  780.       statbuf->st_nlink = sp->cf_nlink;      
  781.  
  782.       Debug("Found in cache\n");
  783.       return true;
  784.       }
  785.    }
  786.  
  787. Debug("Did not find in cache\n"); 
  788. return false;
  789. }
  790.  
  791. /*********************************************************************/
  792.  
  793. CacheData(data,ip)
  794.  
  795. struct cfstat *data;
  796. struct Image *ip;
  797.  
  798. { struct cfstat *sp;
  799.  
  800. if ((sp = (struct cfstat *) malloc(sizeof(struct cfstat))) == NULL)
  801.    {
  802.    CfLog(cferror,"Memory allocation faliure in CacheData()\n","");
  803.    return;
  804.    }
  805.  
  806. bcopy(data,sp,sizeof(struct cfstat));
  807.  
  808. sp->next = ip->cache;
  809. ip->cache = sp;
  810. }
  811.  
  812.